home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
Pakiet bezpieczenstwa
/
mini Pentoo LiveCD 2006.1
/
mpentoo-2006.1.iso
/
livecd.squashfs
/
usr
/
lib
/
metasploit
/
msfupdate
< prev
next >
Wrap
Text File
|
2006-06-30
|
20KB
|
777 lines
#!/usr/bin/perl
###############
require 5.6.0;
use strict;
use vars qw{$SSL_SUPPORT};
use FindBin qw{$RealBin};
use lib "$RealBin/lib";
use Digest::Perl::MD5 qw{md5_hex};
use Getopt::Std;
use IO::Socket;
use IO::Select;
use POSIX;
no utf8;
no locale;
my $VERSION = '$Revision: 1.45 $';
my $FRAMEWORK = '2.6';
my ($REV) = $VERSION =~ m/\$Revisio.:\s+([^\s]+)/;
my $UPDATE_HOST = 'metasploit.com';
my $UPDATE_PATH = '/projects/Framework/updates/msfupdate.html';
my $SSL_VERIFIED = 0;
my $SSL_ISSUER = '/C=US/ST=Texas/L=San Antonio/O=The Metasploit Project/OU=Development/CN=Metasploit CA/emailAddress=cacert@metasploit.com';
my $SSL_CERTS = "$RealBin/docs";
my $OPSYS = $^O;
select(STDOUT); $|++;
# Check for buggy versions of perl with utf-8 locale set
BrokenUTF8();
# Determine if SSL support is enabled
BEGIN
{
if (eval "require Net::SSLeay")
{
Net::SSLeay->import();
Net::SSLeay::load_error_strings();
Net::SSLeay::SSLeay_add_ssl_algorithms();
Net::SSLeay::randomize();
$SSL_SUPPORT++;
}
}
my %opts;
getopts('hrvusmaxfOp:', \%opts);
if ($opts{v}) {
print "Msfupdate Version: $REV\n";
print "Framework Version: $FRAMEWORK\n";
exit(0);
}
if ($opts{h} || (! $opts{m} && ! $opts{r} && ! $opts{u} && ! $opts{U})) {
Usage();
}
if ($opts{O}) {
$OPSYS = 'paranoid';
}
chdir($RealBin);
my $proxy = $opts{'p'};
my ($old_data, $now_data, $new_data);
my ($old, $now, $new);
my ($mod, $upx, $upd);
print "\n";
print "+ -- --=[ msfupdate v$FRAMEWORK [revision $REV]\n\n";
print "[*] Calculating local file checksums, please wait...\n";
$now_data = ScanFiles('.');
print "\n";
if (! -r '.current') {
WriteFile('.current', $now_data);
$old_data = $now_data;
}
else {
$old_data = ReadFile('.current');
}
if ($opts{r}) {
print "[*] The local file hash has been rebuilt\n";
WriteFile('.current', $now_data);
exit(0);
}
# Allow the user to disable SSL mode entirely
if ($opts{f}) {
$SSL_SUPPORT = 0;
}
# Display a big nasty warning for non-SSL unless -x is specified
if ($opts{u} || $opts{U}) {
if (! $opts{x} && ! $SSL_SUPPORT) {
print "[*] WARNING: The Net::SSLeay module is not installed. The update\n";
print " process will fall back to plain HTTP, this may allow a \n";
print " malicious attacker to inject hostile code into your system.\n";
print "\n";
print "Continue anyways (yes or no) ";
my $resp;
while ($resp !~ /yes|no/i) {
print "> ";
$resp = <STDIN>;
chomp($resp);
}
print "\n";
if ($resp !~ /yes/i) {
print "[*] The update process has been cancelled\n";
exit(0);
}
}
$new_data = DownloadFile($UPDATE_HOST, "$UPDATE_PATH/.current", $proxy);
}
$now = Hashit($now_data);
$old = Hashit($old_data);
$new = Hashit($new_data);
$mod = Diff($old, $now);
$upx = Diff($old, $new);
$upd = Diff($now, $new);
if ($opts{m}) {
if (! keys(%{$mod})) {
print "[*] No modifications since the last update\n";
exit(0);
}
print "[*] Modifications since the last update:\n";
foreach (sort keys(%{$mod})) {
print "\t".$mod->{$_}."\t$_\n";
}
print "\n";
exit(0);
}
# Strip this list down to just modifications
foreach (keys(%{$mod})) {
if ($mod->{$_} ne 'Mod') {
delete($mod->{$_});
}
}
if (! $new_data) {
print "[*] Could not obtain the current version information from the update server\n";
exit(0);
}
my $mver = CheckVersion();
if ( ($opts{u} || $opts{U}) && ! $mver) {
print "[*] Could not determine the current Framework version.\n";
exit(0);
}
if ($mver && $mver ne $FRAMEWORK) {
if (! $opts{U}) {
print "[*] Version $mver of the Metasploit Framework is now available.\n";
print " - http://metasploit.com/projects/Framework/downloads.html\n\b\n";
}
else {
print "[*] Starting upgrade process for version $mver...\n\n";
}
}
if ($opts{U} && $mver && $mver eq $FRAMEWORK) {
print "[*] No version upgrade is necessary.\n";
exit(0);
}
# Upgrade to a new major release version...
if ($opts{U}) {
my $backupdir = 'backup_'. $FRAMEWORK;
print "[*] WARNING: You are about to upgrade to a new major version of the\n";
print " Metasploit Framework. This process involves removing the current\n";
print " installation and downloading the new version, one file at a time.\n";
print " This process is slow and somewhat prone to failure. If you encounter\n";
print " any problems during the download, you *should* be able to simply\n";
print " restart msfupdate with the -u parameter\n\n";
print " If you have modified any of the files in the Framework directory,\n";
print " these will be saved to $backupdir. The same applies for any modules\n";
print " that you have added to this Framework installation. After the update\n";
print " is complete, you should be able to copy these modules from the\n";
print " backup directory ($backupdir) into the appropriate directories\n";
print " in the new installation.\n\n";
print " If you are using FreeBSD or any other operating that maintains a\n";
print " package for the Framework, we recommend that you use the system\n";
print " package manager to upgrade\n\n";
print " Please type 'yes' to initiate the upgrade process.\n";
print "Continue? (yes or no) ";
my $resp;
while ($resp !~ /yes|no/i) {
print "> ";
$resp = <STDIN>;
chomp($resp);
}
if ($resp =~ /no/i) {
exit(0);
}
delete($now->{'./msfupdate'});
delete($new->{'./msfupdate'});
delete($mod->{'./msfupdate'});
delete($upd->{'./msfupdate'});
print "[*] Backing up modified files to $backupdir...\n";
# Backup framework files that the user modified
foreach my $file (keys %{$mod} ) {
print " --- MOD $file\n";
my $data = ReadFile($file);
WriteFile($backupdir .'/'. $file , $data);
}
# Backup files that the user created
foreach my $file (keys %{$upd} ) {
next if $upd->{$file} ne 'Del';
print " --- USR $file\n";
my $data = ReadFile($file);
WriteFile($backupdir .'/'. $file , $data);
}
print "[*] Removing the current installation...\n";
# Do not remove these files since we need them to update...
my %docs_save = ('./docs/7f8d5320.0' => 1, './docs/cacert.pem' => 1);
# Remove all files that are part of the framework
foreach my $file (keys %{$now}) {
next if exists($docs_save{$file});
unlink($file);
}
# Remove all directories but 'docs'
foreach my $dir (split(/\n/, ScanDirs('.', 0))) {
next if $dir eq './docs';
system("rm", "-rf", $dir);
}
# Bump up the framework version
$FRAMEWORK = $mver;
# Download the file list for the new framework version
$new_data = DownloadFile($UPDATE_HOST, "$UPDATE_PATH/.current", $proxy);
# Rebuild the tables
$new = Hashit($new_data);
$now = {};
$old = {};
$mod = Diff($old, $now);
$upx = Diff($old, $new);
$upd = Diff($now, $new);
# Configure some options
$opts{a}++;
}
# They modified something, ask them what they want to do with it
if (! $opts{a} && keys(%{$mod})) {
print "[*] You have modified the following Framework components:\n\n";
foreach (sort(keys(%{$mod}))) {
print "\t".$_."\n";
}
print "\n";
print " Would you like to preserve these changes? If you say no, all\n";
print " local modifications will be overwritten by the update process.\n";
print "\n";
print "Preserve modifications (yes or no) ";
my $resp;
while ($resp !~ /yes|no/i) {
print "> ";
$resp = <STDIN>;
chomp($resp);
}
if ($resp =~ /no/i) {
$mod = {};
}
print "\n";
}
foreach (keys(%{$upd})) {
# Do not remove user-created files
if ($upd->{$_} eq 'Del') {
delete($upd->{$_});
}
# Ignore updates we already have
if ($now->{$_} eq $new->{$_}) {
delete($upd->{$_});
}
}
# Ignore locally modified files when -a is supplied
if ($opts{a}) {
$mod = {};
}
# After all of this stuff, this is what we have
# - $mod is a table of anything the user wants to keep
# - $upd is a table of everything online new or updated
# The plan of attack is:
# - Iterate through each item in $upd, if there is a match in
# $mod, we print a message and ignore the download for it.
# We will delete anything with the Del status set in this
# table.
# - Once we have identified an update, we try to download it.
# If an error occurs, either because the download fails or
# the md5 does no match.
#
# - After all files have been processed, we rebuild the local
# .current file and get ready for the next update.
#
if (! keys(%{$upd})) {
print "[*] No new updates are available\n";
exit(0);
}
print "[*] Online Update Task Summary\n\n";
foreach my $entry (sort keys(%{$upd})) {
next if $opts{U};
if ($mod->{$entry}) {
print "\tIgnore: $entry\n";
}
else {
print "\tUpdate: $entry\n";
}
}
print "\n";
exit(0) if $opts{s};
if (! $opts{a}) {
print "Continue? (yes or no) ";
my $resp;
while ($resp !~ /yes|no/i) {
print "> ";
$resp = <STDIN>;
chomp($resp);
}
print "\n";
if ($resp !~ /yes/i) {
exit(0);
}
}
my @tasks = sort(keys(%{$upd}));
# Force msfupdate to downloaded first...
if ($opts{U}) {
unshift(@tasks, './msfupdate');
unshift(@tasks, './lib/Digest/Perl/MD5.pm');
}
my $upd_tot = scalar(@tasks);
my $upd_cur = 0;
print "\n";
print "[*] Starting online update of $upd_tot file(s)...\n\n";
foreach my $entry (@tasks) {
if ($mod->{$entry}) {
next;
}
my $data = DownloadFile($UPDATE_HOST, "$UPDATE_PATH/$entry", $proxy);
if ($new->{$entry} ne md5_hex($data)) {
print "$entry: ". $new->{$entry} ." != ". md5_hex($data) ."\n";
my $errmsg = $data ? 'checksum mismatch' : 'download failed';
print "[*] Failed to update $entry: $errmsg\n";
next;
}
# overwrite the local file O_o
WriteFile($entry, $data);
# set it executable since we dont track permissions
chmod(0755, $entry);
printf("[%.4d/%.4d - 0x%.6x bytes] $entry\n", ++$upd_cur, $upd_tot, length($data));
}
print "\n";
print "[*] Regenerating local file database\n";
$now_data = ScanFiles('.');
WriteFile('.current', $now_data);
sub Usage {
print STDERR " Usage: $0 [options]>\n";
print STDERR "Options:\n";
print STDERR " -h You're looking at me baby\n";
print STDERR " -v Display version information\n";
print STDERR " -u Perform an online update via metasploit.com\n";
print STDERR " -s Only display update tasks, do not actually download\n";
print STDERR " -m Show any files locally modified since last update\n";
print STDERR " -a Do not prompt, default to overwrite all files\n";
print STDERR " -x Do not require confirmation for non-SSL updates\n";
print STDERR " -f Disable ssl support entirely, use with -x to avoid warnings\n";
print STDERR " -O Removes the operating system name from the user agent\n";
print STDERR " -p Specifies a proxy: <http|socks4>:<hostname>:<port>\n";
# Too buggy and dangerous to use
# print STDERR " -U Upgrade to a new major revision of the Framework\n";
# Developer options
# print STDERR " -r Rebuild the local version database (internal only)\n";
print "\n";
exit(0);
}
sub ScanFiles {
my $dir = shift;
my $res;
my $hwn;
opendir ($hwn, $dir) || return;
while (defined(my $entry = readdir($hwn))) {
my $path = "$dir/$entry";
# ignore all symlinks
next if -l $path;
# ignore all leading dot files
next if $entry =~ /^\./;
# ignore the backup directories
next if $entry =~ /^backup_/;
# recurse into directories
if (-d $path) {
$res .= ScanFiles($path);
}
elsif (-f $path) {
$res .= HashFile($path)."\t$path\n";;
}
}
closedir($hwn);
return $res;
}
sub ScanDirs {
my $dir = shift;
my $dep = @_ ? shift() : 0;
my $res;
my $hwn;
return if $dep == -1;
opendir ($hwn, $dir) || return;
while (defined(my $entry = readdir($hwn))) {
my $path = "$dir/$entry";
# ignore all symlinks
next if -l $path;
# ignore the backup directories
next if $entry =~ /^backup_/;
# ignore all leading dot files
next if $entry =~ /^\./;
# recurse into directories
if (-d $path) {
$res .= "$path\n";
$res .= ScanDirs($path, $dep - 1);
}
}
closedir($hwn);
return $res;
}
sub CheckVersion {
my $data = DownloadFile($UPDATE_HOST, $UPDATE_PATH, $proxy);
my ($vers, $mtime) = split(/\s+/, $data);
return $vers;
}
sub DownloadFile {
my $host = shift;
my $path = shift;
my $prox = shift;
my $port = $SSL_SUPPORT ? 443 : 80;
my $data;
$path = EscapeURI($path);
my ($proxy_type, $proxy_host, $proxy_port);
if ($prox =~ m/^(socks4|http):([^:]+):(\d+)/) {
($proxy_type, $proxy_host, $proxy_port) = ($1, $2, $3);
}
if ($prox && ! $proxy_host) {
print STDERR "[*] Invalid proxy format ($prox), please use one of the following:\n";
print STDERR "\tSOCKS: socks4:<hostname|ip address>:<port>\n";
print STDERR "\t HTTP: http:<hostname|ip address>:<port>\n\n";
exit(0);
}
my $sock = IO::Socket::INET->new
(
PeerAddr => $proxy_host || $host,
PeerPort => $proxy_port || $port,
Proto => 'tcp',
);
if (! $sock) {
print STDERR "[*] Could not connect to $host: $!\n";
exit(0);
}
if ($proxy_type eq 'http') {
$sock->send("CONNECT ".$host.":".$port." HTTP/1.0\r\n\r\n");
# Look for the HTTP response message from the Proxy server
my $sel = IO::Select->new($sock);
my $resp = '';
if ($sel->can_read(5)) {
while (my $line = <$sock>) {
last if $line eq "\r\n";
$resp .= $line;
}
} else {
print STDERR "[*] No reply received from the HTTP proxy\n";
exit(0);
}
if ($resp !~ /HTTP\/1\.\d\s+2/) {
foreach my $line (split(/\r\n/, $resp)) {
$line =~ s/\r|\n//g;
$line =~ s/\e//g;
print STDERR "[*] Proxy: " . $line . "\n";
}
print STDERR "[*] Connection failed\n";
exit(0);
}
}
if ($proxy_type eq 'socks4') {
$sock->send("\x04\x01".pack('n',$port).gethostbyname($host)."\x00");
$sock->recv(my $res, 8);
if (! $res || ($res && ord(substr($res,1,1)) != 90)) {
print STDERR "[*] Failed to established connection through socks4 proxy $proxy_host\n";
if (length($res)) {
print STDERR "[*] Response: ". unpack("H*", $res) ."\n";
}
exit(0);
}
}
my $req =
"GET $path HTTP/1.0\r\n".
"Host: ".$host.":".$port."\r\n".
"User-Agent: msfupdate/$REV $FRAMEWORK ($OPSYS)\r\n\r\n";
if ($SSL_SUPPORT) {
# Reset the verified flag
$SSL_VERIFIED = 0;
# Create SSL Context
my $ctx = Net::SSLeay::CTX_new();
# Tell SSL to use the certificate in the docs directory
Net::SSLeay::CTX_load_verify_locations($ctx, '', $SSL_CERTS);
# Configure the SSL call-back to prevent MiTM
Net::SSLeay::CTX_set_verify($ctx, &Net::SSLeay::VERIFY_PEER, \&SSLVerify);
# Configure session for maximum interoperability
Net::SSLeay::CTX_set_options($ctx, &Net::SSLeay::OP_ALL);
# Create a new SSL object with context
my $ssl = Net::SSLeay::new($ctx);
# Bind the SSL descriptor to the socket
Net::SSLeay::set_fd($ssl, $sock->fileno);
# Negotiate connection
my $sslConn = Net::SSLeay::connect($ssl);
if ($sslConn <= 0) {
print STDERR "[*] SSL error:". Net::SSLeay::print_errs()."\n";
$sock->close;
return;
}
Net::SSLeay::ssl_write_all($ssl, $req);
my $cert = Net::SSLeay::get_peer_certificate($ssl);
$data = Net::SSLeay::ssl_read_all($ssl);
Net::SSLeay::free ($ssl);
Net::SSLeay::CTX_free ($ctx);
$sock->close;
$data = ProcessHTTP($data);
return $data;
}
$sock->send($req);
$sock->shutdown(1);
while (<$sock>) { $data .= $_ }
close ($sock);
$data = ProcessHTTP($data);
return $data;
}
# Prevent MiTM attacks on the update downloads when run over SSL
sub SSLVerify {
my ($ok, $x509_store_ctx) = @_;
my $cert = Net::SSLeay::X509_STORE_CTX_get_current_cert($x509_store_ctx);
if ($cert) {
my $x509_issuer = Net::SSLeay::X509_get_issuer_name($cert);
my $issuer = Net::SSLeay::X509_NAME_oneline($x509_issuer);
# differences between openssl 0.9.6 vs 0.9.7 (thanks par!)
$issuer =~ s/Email/emailAddress/g;
if ($ok && $issuer eq $SSL_ISSUER) {
$SSL_VERIFIED++;
return 1;
}
}
return;
}
sub ProcessHTTP {
my $http = shift;
my $idx = index($http, "\r\n\r\n");
return if -1 == $idx;
my $head = substr($http, 0, $idx);
my $body = substr($http, $idx + 4);
return if $head !~ /HTTP\/1..\s+2/;
return $body;
}
sub WriteFile {
my $file = shift;
my $data = shift;
my @path = split(/\//, $file);
pop(@path);
my $cdir = ".";
foreach (@path) {
$cdir .= "/".$_;
if (! -d $cdir) {
mkdir($cdir, 0755);
}
}
open (my $out, ">$file") || return;
print $out $data;
close ($out);
}
sub ReadFile {
my $path = shift;
my $data;
my $inp;
open($inp, "<$path") || return;
while (<$inp>) { $data .= $_ }
close($inp);
return $data;
}
sub HashFile {
my $path = shift;
my $data = ReadFile($path);
return md5_hex($data);
}
sub Hashit {
my $data = shift;
my $hash = {};
foreach my $line (split(/\n/, $data)) {
my ($md5, $path) = $line =~ m/^([^\s]+)\s+(.*)/g;
$hash->{$path} = $md5;
}
return $hash;
}
sub Diff {
my $setA = shift;
my $setB = shift;
my $res;
foreach (keys(%{$setA})) {
if (exists($setB->{$_})) {
if ($setA->{$_} ne $setB->{$_}) {
$res->{$_} = 'Mod';
}
}
else {
$res->{$_} = 'Del';
}
}
foreach (keys(%{$setB})) {
if (! exists($setA->{$_})) {
$res->{$_} = 'New';
}
}
return $res;
}
sub EscapeURI {
my $path = shift;
my %escapes = ();
for (0..255) { $escapes{chr($_)} = sprintf("%%%02X", $_) }
$path =~ s/([^A-Za-z0-9\-_.!~*'()\/])/$escapes{$1}/eg;
return $path;
}
sub BrokenUTF8 {
if ( $] >= 5.008 && $] < 5.008002 )
{
my $badver;
# Check LANG first
$badver = ($ENV{'LANG'} =~ /utf/i) ? 1 : 0;
# LC_ALL overrides LANG if its set
if (defined($ENV{'LC_ALL'})) {
$badver = ($ENV{'LC_ALL'} =~ /utf/i) ? 1 : 0;
}
return if ! $badver;
print STDERR qq|
[*] This version of Perl ($]) contains a buggy utf-8 implementation. If you
would like to use this version with the Metasploit Framework, you must
set the LC_ALL environment variable to 'C'. For example:
\$ export LC_ALL=C; ./msfconsole
|;
exit(0);
}
}